@ /0  ; Inicio absoluto do codigo

Inicio JP PRINCIPAL  ; Desvio para o PRINCIPAL

BufIOFim  K BufIO  ; Ponteiro para fim do buffer IO
BufIO     $ =8
TMP0      K /0
TMP1      K /0
TMP2      K /0
TMP3      K /0
TMP4      K /0
TMP5      K /0
SP        K /0
FP        K /0
FPTMP     K /0
CP0       K /0     ; Parametro origem para a funcao COPY
CP1       K /0     ; Parametro destino para a funcao COPY
CP2       K /0     ; Parametro com tamanho do destino para a funcao COPY
TMPR      K /0
TMPP      K /0
; Constantes Numericas
DoisHex   K /2
TrintaHex K /30
CemHex    K /100
DezDec    K =10
DezMilDec K =10000
; Constantes Caracteres
CR        K /d
LF        K /a
Sinal     K /2d
Sinal_    K /2d20
; Constantes Operadores
Store     MM /0    ; Base para instrucao de store
Load      LD /0    ; Base para instrucao de load
Soma      +  /0    ; Base para instrucao de soma
VAR_i K /0
VAR_saida $ =4

PRINCIPAL LV BP  ; Inicializa ponteiros de pilha
MM SP            ; Inicializa stack pointer
MM FP            ; Inicializa frame pointer
SC READ_INT
MM VAR_i
LV =0
MM TMP0
LV VAR_saida
+ TMP0
+ Store
MM INSTR0
LV =82
* CemHex
/ CemHex
INSTR0 MM /0
LV TMP0 ; Armazena os temporarios no RA
MM CP0
LV =6
+ SP
MM CP1
LV =12
MM CP2
SC COPY ; Chama a rotina de copia
LD VAR_i
MM TMP0
LV =18
+ SP
+ Store
MM INSTR1
LD TMP0
INSTR1 MM /0
LV =20
SC PUSH ; Inicio da chamada da funcao
SC FUNC_fatorialRecursivo
MM TMP0
LV =2
MM TMP1
LV VAR_saida
+ TMP1
+ Store
MM INSTR2
LD TMP0
INSTR2 MM /0
LV =4
MM TMP0
LV VAR_saida
+ TMP0
+ Store
MM INSTR3
LV =73
* CemHex
/ CemHex
INSTR3 MM /0
LD VAR_i
MM TMP0
LV =6
MM TMP1
LV VAR_saida
+ TMP1
+ Store
MM INSTR4
LD TMP0
INSTR4 MM /0
LV TMP0 ; Armazena os temporarios no RA
MM CP0
LV =6
+ SP
MM CP1
LV =12
MM CP2
SC COPY ; Chama a rotina de copia
LV VAR_saida
MM CP0
LV =18
+ SP
MM CP1
LV =8
MM CP2
SC COPY
LV =26
SC PUSH ; Inicio da chamada da funcao
SC FUNC_fatorialIterativo
MM TMP0
LV =6
MM TMP1
LV VAR_saida
+ TMP1
+ Store
MM INSTR5
LD TMP0
INSTR5 MM /0
LV =124
* CemHex
/ CemHex
SC WRITE
LV =0
MM TMP0
LV VAR_saida
+ TMP0
+ Load
MM INSTR6
INSTR6 LD /0
MM TMP0
LD TMP0
* CemHex
/ CemHex
SC WRITE
LV =2
MM TMP0
LV VAR_saida
+ TMP0
+ Load
MM INSTR7
INSTR7 LD /0
MM TMP0
LD TMP0
SC WRITE_INT
LV =124
* CemHex
/ CemHex
SC WRITE
LV =4
MM TMP0
LV VAR_saida
+ TMP0
+ Load
MM INSTR8
INSTR8 LD /0
MM TMP0
LD TMP0
* CemHex
/ CemHex
SC WRITE
LV =6
MM TMP0
LV VAR_saida
+ TMP0
+ Load
MM INSTR9
INSTR9 LD /0
MM TMP0
LD TMP0
SC WRITE_INT
LV =124
* CemHex
/ CemHex
SC WRITE
HM /0  ; FIM do PRINCIPAL
FUNC_fatorialRecursivo K /0  ;
LV /2 ; 
+ FP ; 
+ Store ; 
MM INSTR10 ; 
LD FUNC_fatorialRecursivo ; 
INSTR10 MM /0 ; 
LV =2 ; 
+ SP ; 
MM SP ; 
LV =18
+ FP
+ Load
MM INSTR11
INSTR11 LD /0
MM TMP0
LV =1
- TMP0
JN CMP5_F12
LV /1
JP END_CMP513
CMP5_F12 LV /0
END_CMP513 MM TMP0
LD TMP0 ; Abertura de if
JZ ENDIF14
LV =20
+ FP
+ Store
MM INSTR15
LV =1
INSTR15 MM /0
JP ENDELSE14
ENDIF14 LV /0 ; NOP
LV =18
+ FP
+ Load
MM INSTR16
INSTR16 LD /0
MM TMP0
LV TMP0 ; Armazena os temporarios no RA
MM CP0
LV =6
+ SP
MM CP1
LV =12
MM CP2
SC COPY ; Chama a rotina de copia
LV =18
+ FP
+ Load
MM INSTR17
INSTR17 LD /0
MM TMP1
LV =1
MM TMP2
LD TMP1
- TMP2
MM TMP1
LV =18
+ SP
+ Store
MM INSTR18
LD TMP1
INSTR18 MM /0
LV =20
SC PUSH ; Inicio da chamada da funcao
SC FUNC_fatorialRecursivo
MM TMP1
LD TMP0
* TMP1
MM TMP0
LV =20
+ FP
+ Store
MM INSTR19
LD TMP0
INSTR19 MM /0
ENDELSE14 LV /0 ; NOP
LV =20
+ FP
+ Load
MM INSTR20
INSTR20 LD /0
MM TMP0
LD TMP0 ; 
MM TMPR ; 
LV =6 ; 
+ FP ; 
MM CP0 ; 
LV TMP0 ; 
MM CP1 ; 
LV =12 ; 
MM CP2 ; 
SC COPY ; 
LV /2 ; 
+ FP ; 
+ Load ; 
MM END21 ; 
END21 LD /0 ; 
MM FUNC_fatorialRecursivo ; 
SC POP ; 
LD TMPR ; 
RS FUNC_fatorialRecursivo ; 
FUNC_fatorialIterativo K /0  ;
LV /2 ; 
+ FP ; 
+ Store ; 
MM INSTR22 ; 
LD FUNC_fatorialIterativo ; 
INSTR22 MM /0 ; 
LV =2 ; 
+ SP ; 
MM SP ; 
LV =26
+ FP
+ Store
MM INSTR23
LV =1
INSTR23 MM /0
WHILE24 LV =6
MM TMP0
LV =18
+ TMP0
+ FP
+ Load
MM INSTR25
INSTR25 LD /0
MM TMP0
LV =0
MM TMP1
LD TMP0
- TMP1
JZ CMP2_F26
JN CMP2_F26
LV /1
JP END_CMP227
CMP2_F26 LV /0
END_CMP227 MM TMP0
LD TMP0 ; Carrega condicao do while
JZ ENDWHILE24
LV =26
+ FP
+ Load
MM INSTR28
INSTR28 LD /0
MM TMP0
LV =6
MM TMP1
LV =18
+ TMP1
+ FP
+ Load
MM INSTR29
INSTR29 LD /0
MM TMP1
LD TMP0
* TMP1
MM TMP0
LV =26
+ FP
+ Store
MM INSTR30
LD TMP0
INSTR30 MM /0
LV =6
MM TMP0
LV =18
+ TMP0
+ FP
+ Load
MM INSTR31
INSTR31 LD /0
MM TMP0
LV =1
MM TMP1
LD TMP0
- TMP1
MM TMP0
LV =6
MM TMP1
LV =18
+ TMP1
+ FP
+ Store
MM INSTR32
LD TMP0
INSTR32 MM /0
JP WHILE24
ENDWHILE24 LV /0 ; NOP
LV =26
+ FP
+ Load
MM INSTR33
INSTR33 LD /0
MM TMP0
LD TMP0 ; 
MM TMPR ; 
LV =6 ; 
+ FP ; 
MM CP0 ; 
LV TMP0 ; 
MM CP1 ; 
LV =12 ; 
MM CP2 ; 
SC COPY ; 
LV /2 ; 
+ FP ; 
+ Load ; 
MM END34 ; 
END34 LD /0 ; 
MM FUNC_fatorialIterativo ; 
SC POP ; 
LD TMPR ; 
RS FUNC_fatorialIterativo ; 

; SUBROTINA READ
; Faz a leitura de caracteres digitados no teclado e preenche o buffer IO
; Retorna no acumulador o primeiro caracter lido
READ K /0       
LV BufIO
MM BufIOFim     ; Reseta referencia de fim do buffer IO
LeCharR GD /0   ; Pega dados do dispositivo
MM TMP2         ; Armazena leitura
/ CemHex
MM TMP1         ; Retira primeiro char e armazena em TMP1
- CR
JZ ENDREAD      ; Se achou CR acabou s sequencia
LD TMP1
- LF
JZ ENDREAD      ; Se acho LF acabou a sequencia

LD BufIOFim     ; Monta instrucao de preecher buffer IO
+ Store
MM GuardaR1     ; Salva instrucao de preecher buffer IO
LD TMP1
GuardaR1 MM /0  ; Armazena primeiro char (instrucao montada dinamicamente)
LV /2
+ BufIOFim
MM BufIOFim     ; Atualiza referencia

LD TMP2
* CemHex
/ CemHex
MM TMP1         ; Retira segundo char
- CR
JZ ENDREAD      ; Se achou CR acabou sequencia
LD TMP1
- LF
JZ ENDREAD      ; Se acho LF acabou a sequencia

LD BufIOFim     ; Monta instrucao de preecher buffer IO
+ Store
MM GuardaR2     ; Salva instrucao de preecher buffer IO
LD TMP1
GuardaR2 MM /0  ; Armazena segundo char
LV /2
+ BufIOFim     ; Atualiza ponteiro
MM BufIOFim

JP LeCharR

ENDREAD LD BufIO  ; Carrega o primeiro char lido no AC
RS READ ; FIM DA SUBROTINA READ

; SUB-ROTINA READ_INT
; Recebe uma sequencia numerica pela rotina READ e converte para um
; inteiro que e retornado no acumulador
READ_INT K /0
SC READ
LV /0
MM TMP1           ; TMP1 contem o resultado
LV BufIO
MM TMP2           ; TMP2 contem o ponteiro de char

LD BufIO          ; Verifica se o primeiro char e de sinal "-"
- Sinal
JZ NegativoRI
LV /0
MM TMP3           ; Inicializa flag (TMP3) indicando que nao ha sinal
JP LeCharRI
NegativoRI LV /1  ; Sobe a flag (TMP3) indicando a necessidade de correcao de sinal
MM TMP3
LV /2
+ TMP2
MM TMP2           ; Atualiza a referencia para o buffer IO

LeCharRI LD TMP1
* DezDec          ; Multiplica o resultado parcial por 10
MM TMP1
LD TMP2
+ Load
MM CarregaRI
CarregaRI LD /0   ; Carrega char no buffer IO
- TrintaHex       ; Corrige para inteiro
+ TMP1            ; Acrescenta no resultado parcial
MM TMP1
LV /2             ; Incrementa ponteiro para buffer IO
+ TMP2
MM TMP2
- BufIOFim        ; Compara com o fim do buffer IO
JN LeCharRI       ; Se for diferente volta a ler o proximo caracter
 
LD TMP3
JZ ResRI          ; Inverte o sinal do resultado caso TMP3
LV /0
- TMP1
MM TMP1
ResRI LD TMP1     ; Carrega o resultado para o acumulador
 
RS READ_INT ; FIM DA SUB-ROTINA READ_INT

; SUB-ROTINA WRITE
; Recebe um caracter no acumulador e imprime
WRITE K /0
* CemHex
PD /100
RS WRITE ; FIM DA SUB-ROTINA WRITE

; SUB-ROTINA WRITE_INT
; Recebe um inteiro no acumulador, converte para a representacao em caracteres e
; imprime (devido a limitacao da MVN o numero aparece quebrado entre diversas linhas)
WRITE_INT K /0

MM TMP1                 ; TMP1 contem o numero a ser impresso
JN NegativoWI           ; Verifica se o numero e negativo
JP IniciaRefWI
NegativoWI LV /0        ; Se negativo corrige numero e imprime sinal
- TMP1
MM TMP1                 ; TMP1 contem o numero a ser impresso
LD Sinal_                
PD /100                 ; Imprime "- "

IniciaRefWI LD DezMilDec
MM TMP2                 ; TMP2 referencia o digito a ser impresso

PulaZerosWI LD TMP2
JZ Imprime0WI           ; Caso a ref. percorreu todo o num., imprime "0"
SC AUX_WRITE_INT        ; Pega o primeiro digito
JZ PulaZerosWI          ; Se o digito for zero, desloca a ref.
+ TrintaHex             ; Converte para caracter (ASCII)
* CemHex                ; Posiciona no buffer (byte mais sig.)
MM BufIO                ; Salvar no buffer
JP PegaD2WI

PegaD1WI LD TMP2        ; Carrega a ref.
JZ FimWI                ; Verifica se a ref. percorreu todo o num.
SC AUX_WRITE_INT        ; Pega proximo digito
+ TrintaHex             ; Converte para caracter (ASCII)
* CemHex                ; Posiciona no buffer (byte mais sig.)
MM BufIO                ; Salvar no buffer
PegaD2WI LD TMP2
JZ ImprimeWI            ; Verifica se a ref. percorreu todo o num.
SC AUX_WRITE_INT        ; Pega proximo digito
+ TrintaHex             ; Converte para caracter (ASCII)
+ BufIO                 ; Posiciona no buffer (byte menos sig.)
MM BufIO                ; Salvar no buffer

ImprimeWI LD BufIO      ; Carrega o buffer IO
PD /100                 ; Imprime na tela o par de caracteres
JP PegaD1WI             ; Reinicia processo de obtencao de dig.

Imprime0WI LV /30       ; Imprime "0"
PD /100

FimWI RS WRITE_INT ; FIM DA SUB-ROTINA WRITE_INT

; SUB-ROTINA AUX_WRITE_INT
; Rotina de uso interno do WRITE_INT
; Atualiza referencias usadas para isolar digito
AUX_WRITE_INT K /0
LD TMP1
/ TMP2      ; Pega valores a esquerda
/ DezDec
* DezDec
MM TMP3
LD TMP1     ; Isola digito
/ TMP2
- TMP3
MM TMP3     ; Guarda o digito
LD TMP2     ; Desloca ref. de TMP2 em um digito para o lado
/ DezDec
MM TMP2
LD TMP3     ; Restaura digito retirado
RS AUX_WRITE_INT

; SUBROTINA PUSH
; Aloca espaco na pilha de acordo com o espaco determinado no acumulador
; Preenche automaticamente o endereco do RA anterior e o display com este mesmo
; endereco
PUSH K /0
MM TMPP   ; Guarda o tamanho requisitado
LD FP
MM FPTMP  ; Guarda o end. do RA atual
LD SP
MM FP     ; Desloca FP
LD TMPP
+ SP
MM SP     ; Desloca SP

LD FP
+ Store
MM DisplayPush ; Monta instrucao para preencher display padrao
LD FPTMP
DisplayPush MM /0 ; Instrucao montada para salvar o display
               ; com o valor do RA anterior

LV /4
+ FP
+ Store
MM RAAntPush ; Monta instrucao para preencher end. do RA anterior padrao
LD FPTMP
RAAntPush MM /0 ; Instrucao montada para salvar o end. do RA anterior

RS PUSH ; FIM DA SUBROTINA PUSH

; SUBROTINA POP
; Desaloca espaco na pilha, usa como referencia o valor presente no campo
; endereco do RA anterior
POP K /0

LD FP
MM SP

LV /4
+ FP
+ Load
MM RAAntPop ; Monta instrucao para preencher end. do RA anterior padrao
RAAntPop LD /0 ; Instrucao montada para salvar o end. do RA anterior
MM FP

RS POP ; FIM DA SUBROTINA POP

; SUBROTINA COPY
; Rotina que recebe como primeiro parametro um endereco de origem e como segundo um
; endereco de destino. O terceiro parametro e o tamanho em bytes a ser copiado
; Utilizado para transferir para um RA os dados de um vetor ou uma estrutura
COPY K /0

CopyWordC LD CP2
JZ EndC
LD CP2  ; Desconta -2 do tamanho a ser copiado
- DoisHex
MM CP2
; Monta a instrucao de carregar a WORD
LD CP0
+ Load
MM LeOrigC
; Monta a instrucao de copiar a WORD
LD CP1
+ Store
MM SalvaDestC

LeOrigC LD /0
SalvaDestC MM /0

LV /2    ; Avanca uma WORD na origem
+ CP0
MM CP0
LV /2    ; Avanca uma WORD no destino
+ CP1
MM CP1
JP CopyWordC

EndC RS COPY ; FIM DA SUBROTINA COPY

BP        K /0
# Inicio
